package io.openaev.utils.mapper;

import io.openaev.config.cache.LicenseCacheManager;
import io.openaev.database.model.Cwe;
import io.openaev.database.model.Vulnerability;
import io.openaev.ee.Ee;
import io.openaev.rest.cve.form.CVEBulkInsertInput;
import io.openaev.rest.cve.form.CveCreateInput;
import io.openaev.rest.vulnerability.form.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
@Slf4j
public class VulnerabilityMapper {

  private final Ee eeService;
  private final LicenseCacheManager licenseCacheManager;

  public VulnerabilitySimple toVulnerabilitySimple(final Vulnerability vulnerability) {
    if (vulnerability == null) {
      return null;
    }
    return VulnerabilitySimple.builder()
        .id(vulnerability.getId())
        .externalId(vulnerability.getExternalId())
        .cvssV31(vulnerability.getCvssV31())
        .published(vulnerability.getPublished())
        .build();
  }

  public VulnerabilityOutput toVulnerabilityOutput(final Vulnerability vulnerability) {
    if (vulnerability == null) {
      return null;
    }
    return VulnerabilityOutput.builder()
        .id(vulnerability.getId())
        .externalId(vulnerability.getExternalId())
        .cvssV31(vulnerability.getCvssV31())
        .published(vulnerability.getPublished())
        .sourceIdentifier(vulnerability.getSourceIdentifier())
        .description(vulnerability.getDescription())
        .vulnStatus(vulnerability.getVulnStatus())
        .cisaActionDue(vulnerability.getCisaActionDue())
        .cisaExploitAdd(vulnerability.getCisaExploitAdd())
        .cisaRequiredAction(vulnerability.getCisaRequiredAction())
        .cisaVulnerabilityName(vulnerability.getCisaVulnerabilityName())
        .remediation(getRemediationIfLicensed(vulnerability))
        .referenceUrls(new ArrayList<>(vulnerability.getReferenceUrls()))
        .cwes(toCweOutputs(vulnerability.getCwes()))
        .build();
  }

  public VulnerabilityBulkInsertInput fromCVEBulkInsertInput(final CVEBulkInsertInput input) {
    if (input == null) {
      return null;
    }

    VulnerabilityBulkInsertInput result = new VulnerabilityBulkInsertInput();
    result.setVulnerabilities(toVulnerabilityCreateInputs(input.getCves()));
    result.setLastModifiedDateFetched(input.getLastModifiedDateFetched());
    result.setLastIndex(input.getLastIndex());
    result.setInitialDatasetCompleted(input.getInitialDatasetCompleted());
    result.setSourceIdentifier(input.getSourceIdentifier());
    return result;
  }

  private List<VulnerabilityCreateInput> toVulnerabilityCreateInputs(
      final List<CveCreateInput> cves) {
    if (cves == null) {
      return List.of();
    }
    return cves.stream().map(this::toVulnerabilityCreateInput).collect(Collectors.toList());
  }

  private VulnerabilityCreateInput toVulnerabilityCreateInput(final CveCreateInput cve) {
    if (cve == null) {
      return null;
    }

    VulnerabilityCreateInput input = new VulnerabilityCreateInput();
    input.setExternalId(cve.getExternalId());
    input.setSourceIdentifier(cve.getSourceIdentifier());
    input.setCvssV31(cve.getCvssV31());
    input.setPublished(cve.getPublished());
    input.setDescription(cve.getDescription());
    input.setVulnStatus(cve.getVulnStatus());
    input.setCisaExploitAdd(cve.getCisaExploitAdd());
    input.setCisaActionDue(cve.getCisaActionDue());
    input.setCisaRequiredAction(cve.getCisaRequiredAction());
    input.setCisaVulnerabilityName(cve.getCisaVulnerabilityName());
    input.setRemediation(cve.getRemediation());
    input.setReferenceUrls(cve.getReferenceUrls());
    input.setCwes(cve.getCwes());
    return input;
  }

  private List<CweOutput> toCweOutputs(final List<Cwe> cwes) {
    if (cwes == null || cwes.isEmpty()) {
      return Collections.emptyList();
    }
    return cwes.stream().map(this::toCweOutput).collect(Collectors.toList());
  }

  public CweOutput toCweOutput(final Cwe cwe) {
    if (cwe == null) {
      return null;
    }
    return CweOutput.builder().externalId(cwe.getExternalId()).source(cwe.getSource()).build();
  }

  private String getRemediationIfLicensed(final Vulnerability vulnerability) {
    if (eeService.isLicenseActive(licenseCacheManager.getEnterpriseEditionInfo())) {
      return vulnerability.getRemediation();
    } else {
      log.debug("Enterprise Edition license inactive - omitting remediation field");
      return null;
    }
  }
}
